/*************************************************************************/
/*                                                                       */
/*  Copyright (c) 1994 Stanford University                               */
/*                                                                       */
/*  All rights reserved.                                                 */
/*                                                                       */
/*  Permission is given to use, copy, and modify this software for any   */
/*  non-commercial purpose as long as this copyright notice is not       */
/*  removed.  All other uses, including redistribution in whole or in    */
/*  part, are forbidden without prior written permission.                */
/*                                                                       */
/*  This software is provided with absolutely no warranty and no         */
/*  support.                                                             */
/*                                                                       */
/*************************************************************************/


/*
 * NAME
 *	husetup.c
 *
 * DESCRIPTION
 *	This file contains routines that initialize, build, traverse, and
 *	intersect the hierarchical uniform grid (HUG) representation of the scene.
 *
 */


#include <stdio.h>
#include <math.h>
#include "rt.h"



/*
 * NAME
 *	Huniform_defaults - setup the five HUG parameter defaults
 *
 * SYNOPSIS
 *	VOID	Huniform_defaults()
 *
 * RETURNS
 *	Nothing.
 */

VOID	Huniform_defaults()
{
    hu_max_prims_cell   = 2;
    hu_gridsize	    = 5;
    hu_numbuckets	    = 23;
    hu_max_subdiv_level = 1;
    hu_lazy 	    = 0;
}



/*
 * NAME
 *	BuildHierarchy_Uniform - build HU grid from model
 *
 * SYNOPSIS
 *	VOID	BuildHierarchy_Uniform()
 *
 * RETURNS
 *	Nothing.
 *
 */

VOID	BuildHierarchy_Uniform()
{
    INT	num_pe;
    GRID	*g;
    GRID	*ng;
    VOXEL	*v;
    ELEMENT **pepa;

    init_masks();


    pepa = MakeElementArray(&num_pe);

    v = init_world_voxel(pepa,num_pe);

    gm->world_level_grid = init_world_grid(v, pepa, num_pe);
    g = gm->world_level_grid;

    ng = create_grid(v, g, num_pe);

    fprintf(stderr, "Uniform Hierarchy built.\n");
}



/*
 * NAME
 *	IntersectHuniformPrimlist - intersect ray with objects in HU cell
 *
 * SYNOPSIS
 *	VOID	IntersectHuniformPrimlist(intersectPrim, hit, plist, r, pid)
 *	BOOL	*intersectPrim; 	// Primitive hit?
 *	IRECORD *hit;			// Intersection record.
 *	ELEMENT **plist;		// Primitive element list.
 *	RAY	*r;			// Original ray.
 *	INT	pid;			// Process id.
 *
 * RETURNS
 *	Nothing.
 *
 */
VOID    IntersectHuniformPrimlist(INT *intersectPrim, IRECORD *hit, VOXEL *v, RAY *r, INT pid)
{
    ELEMENT **pptr;         /* Primitive element list ptr.       */
    OBJECT  *peParent;      /* Ptr to parent object.         */
    ELEMENT *pe;            /* Primitive element ptr.        */
    IRECORD newhit[ISECT_MAX];  /* Hit recorder.             */
    INT hitcode,i;
    REAL    t_out;

        REAL    b, disc, t1, t2, vsq;       /* Formula variables.        */
        SPHERE  *ps;                /* Ptr to sphere data.       */
        POINT   V;              /* C - P             */
        
    t_out = r->ri->t_out;
    hit[0].t = HUGE_REAL;
    pptr = (ELEMENT**)v->cell;

    for (i = 0; i < v->numelements; i++)
    {
        pe   = pptr[i];
        peParent = pe->parent;

        // if dsp ready/done
           //use data, send new
           
        // else
            //...
            
           
        
        
        
        if (peParent->procs->pe_intersect == PolyPeIntersect){
            hitcode  = (*peParent->procs->pe_intersect)(r, pe, newhit);
            if (hitcode)
                if (newhit[0].t < hit[0].t && newhit[0].t < t_out)
                    hit[0] = newhit[0];
        }
        else if (peParent->procs->pe_intersect == SphPeIntersect){
            
            ps  = (SPHERE *)(pe->data);

            VecSub(V, ps->center, r->P);       /* Ray from origin to center.*/
            vsq = VecDot(V, V);         /* Length sq of V.       */
            b   = VecDot(V, r->D);         /* Perpendicular scale of V. */

            disc = b*b - vsq + ps->rad2;        /* Discriminate.         */

            if (disc < 0.0){             /* Misses ray.           */
            // return (0);
            }
            else {

            disc = sqrt(disc);          /* Find intersection param.  */
            t2   = b + disc;
            //t1   = b - disc;

            //IsectAdd(newhit, t2, pe);       /* Exiting sphere        */

            if (t2 < hit[0].t && t2 < t_out)
                IsectAdd(hit, t2, pe);
                 
            }
        }


    }

    if (hit[0].t < HUGE_REAL)
        *intersectPrim = TRUE;
    else
        *intersectPrim = FALSE;
}



/*
 * NAME
 *	HuniformShadowIntersect - intersect shadow ray with objects in HU cell
 *
 * SYNOPSIS
 *	REAL	HuniformShadowIntersect(r, lightlength, pe, pid)
 *	RAY	*r;			// Incident ray.
 *	REAL	lightlength;		// Distance to light.
 *	ELEMENT *pe;			// Primitive element of shadow ray origin.
 *	INT	pid;			// Process number.
 *
 * RETURNS
 *	Transparency value along ray to light.
 *
 */

REAL    HuniformShadowIntersect(RAY *r, REAL lightlength, ELEMENT *pe, INT pid)
{
    INT status;
    INT hitcode,i;
    REAL    trans;          /* Transparency factor.          */
    OBJECT  *peParent;      /* Ptr to parent object.         */
    ELEMENT **pptr;         /* Primitive element list ptr.       */
    ELEMENT *pe2;           /* Ptr to element.           */
    IRECORD newhit[ISECT_MAX];  /* Hit record.               */
    VOXEL   *v;

    

    
        REAL    b, disc, t1, t2, vsq;       /* Formula variables.        */
        SPHERE  *ps;                /* Ptr to sphere data.       */
        POINT   V;              /* C - P             */
      trans = 1.0;  
    /* Now try uniform hierarchy. */

    r->ri = NULL;
    v = init_ray(r, gm->world_level_grid);

    if (v == NULL)
    {
        reset_rayinfo(r);
        return(trans);
    }

    newhit[0].t = HUGE_REAL;
    status      = IN_WORLD;

    while (trans > 0.0 && status != EXITED_WORLD)
    {
        /* Intersect primitives in cell. */

        pptr = (ELEMENT**)v->cell;

        for (i = 0; (i < v->numelements) && (trans > 0.0); i++)
        {
            pe2  = pptr[i];
            peParent = pe2->parent;
                        
            if (peParent->procs->pe_intersect == PolyPeIntersect){
                hitcode  = (*peParent->procs->pe_intersect)(r, pe2, newhit); 
                if (hitcode && newhit[0].pelem != pe && newhit[0].t < lightlength)
                    trans *= newhit[0].pelem->parent->surf->ktran;
            }
            else if (peParent->procs->pe_intersect == SphPeIntersect){
                
                ps  = (SPHERE *)(pe2->data);

                VecSub(V, ps->center, r->P);       /* Ray from origin to center.*/
                vsq = VecDot(V, V);         /* Length sq of V.       */
                b   = VecDot(V, r->D);         /* Perpendicular scale of V. */

                disc = b*b - vsq + ps->rad2;        /* Discriminate.         */

                if (disc < 0.0){             /* Misses ray.           */
                // return (0);
                //hitcode = 0;
                }
                else {

                disc = sqrt(disc);          /* Find intersection param.  */
                t2   = b + disc;
                //t1   = b - disc;

                IsectAdd(newhit, t2, pe2);       /* Exiting sphere        */
                //hitcode = 1;

                if (newhit[0].pelem != pe && newhit[0].t < lightlength)
                   trans *= newhit[0].pelem->parent->surf->ktran;
               
                    
                }
            }
//           if (hitcode && newhit[0].pelem != pe && newhit[0].t < lightlength)
//               trans *= newhit[0].pelem->parent->surf->ktran;
        }

        if (trans > 0.0)
            v = next_nonempty_leaf(r, STEP, &status);
    }

    reset_rayinfo(r);
    return (trans);
}



/*
 * NAME
 *	TraverseHierarchyUniform - walk the HU grid to intersect a ray
 *
 * SYNOPSIS
 *	BOOL	TraverseHierarchyUniform(r, hit, pid)
 *	RAY	*r;
 *	IRECORD *hit;
 *	INT	pid;
 *
 * RETURNS
 *	TRUE if the ray hit something, FALSE otherwise.
 *
 */

BOOL	TraverseHierarchyUniform(RAY *r, IRECORD *hit, INT pid)
{
    INT	status;
    INT	intersectPrim;
    VOXEL	*v;

    r->ri = NULL;
    v = init_ray(r, gm->world_level_grid);

    if (v == NULL)
    {
        reset_rayinfo(r);
        return (FALSE);
    }

    intersectPrim = FALSE;
    hit[0].t      = HUGE_REAL;
    status	      = IN_WORLD;

    while (!intersectPrim && status != EXITED_WORLD)
    {
        IntersectHuniformPrimlist(&intersectPrim, hit, v, r, pid);

        if (!intersectPrim)
            v = next_nonempty_leaf(r, STEP, &status);
    }

    reset_rayinfo(r);
    return (intersectPrim);
}

